package cn.mw.cmdb.link.strategy.handler;

import cn.mw.cmdb.entity.InstanceInfoExtend;
import cn.mw.cmdb.link.entity.LinkHistoryTrendDto;
import cn.mw.cmdb.link.entity.MwLinkCountDto;
import cn.mw.cmdb.link.entity.MwLinkTargetIpInfo;
import cn.mw.cmdb.link.entity.MwNetWorkLinkDto;
import cn.mw.cmdb.link.enums.LinkDetectionWayEnum;
import cn.mw.cmdb.link.enums.LinkHistoryTypeEnum;
import cn.mw.cmdb.link.param.LinkParam;
import cn.mw.cmdb.link.strategy.LinkDetectionWayHandler;
import cn.mw.cmdb.param.zabbixResult.ItemApplication;
import cn.mw.cmdb.util.BaseUtil;
import cn.mw.microMonitorCommon.constants.ZabbixApiConstants;
import cn.mw.microMonitorCommon.entity.UnitResult;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import cn.mw.microMonitorCommon.util.UnitUtil;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @description NQA方式处理
 */
@Service
@Slf4j
public class LinkNQAWayHandler extends LinkDetectionWayHandler {

    private final String NQA_SUCESS = "NQA_SUCESS";
    private final String NQA_SENT = "NQA_SENT";

    @Override
    public LinkDetectionWayEnum handlerType() {
        return LinkDetectionWayEnum.NQA;
    }

    @Override
    public void getLinkMonitorInfo(List<MwNetWorkLinkDto> dtos) throws Exception {
        List<String> itemNames = new ArrayList<>();
        //查询NQA线路的状态，响应时间，丢包率
        List<String> assetIds = new ArrayList<>();
        for (MwNetWorkLinkDto dto : dtos) {
            String takeValuePort = dto.getTakeValuePort();
            if(takeValuePort.equals(ROOT)){
                assetIds.add(dto.getSourceDeviceAsset());
            }
            if(takeValuePort.equals(TARGET)){
                assetIds.add(dto.getTargetDeviceAsset());
            }
            itemNames.add("["+dto.getDetectionTargetIp()+"]"+NQA_SUCESS);
            itemNames.add("["+dto.getDetectionTargetIp()+"]"+PING_AVGRTT);
            itemNames.add("["+dto.getDetectionTargetIp()+"]"+NQA_SENT);
        }
        //获取资产
        List<InstanceInfoExtend> assetInfo = getTargetDeviceAssetInfo(null, null,assetIds);
        if(CollectionUtils.isEmpty(assetInfo)){return;}
        Map<Integer, List<String>> serverGroup = getHostIdGroup(assetInfo);
        log.info("LinkNQAWayHandler{} getLinkMonitorInfo() serverGroup>>>>>"+serverGroup);
        log.info("LinkNQAWayHandler{} getLinkMonitorInfo() itemNames>>>>>"+itemNames);
        //查询zabbix数据
        List<ItemApplication> itemApplications = getLinkZabbixMonitorInfo(serverGroup, itemNames);
        log.info("LinkNQAWayHandler{} getLinkMonitorInfo() itemApplications>>>>>"+itemApplications);
        if(CollectionUtils.isEmpty(itemApplications)){return;}
        for (MwNetWorkLinkDto dto : dtos) {
            MwLinkCountDto countDto = setNqaValueInfo(dto, itemApplications);
            if(countDto.getNqaSent() != null && countDto.getNqaSucess() != null){
                if(countDto.getNqaSent() == 0 || countDto.getNqaSucess() == 0){continue;}
                log.info("LinkNQAWayHandler{} getLinkMonitorInfo() nqaSent()>>>>"+countDto.getNqaSent()+">>>NqaSucess>>>"+countDto.getNqaSent());
                //计算丢包率
                double v = (countDto.getNqaSent() - countDto.getNqaSucess()) / countDto.getNqaSent();
                String loss = new BigDecimal(v*100).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
                dto.setLossRate(loss+LOSS_RATE_UNIT);
            }
        }
        getLinkBandWidthUtilization(dtos);
    }

    @Override
    public List<MwLinkTargetIpInfo> getTargetIpInfo(LinkParam linkParam) throws Exception {
        List<MwLinkTargetIpInfo> targetIpInfos = new ArrayList<>();
        //查询zabbix上的IP信息
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_TYPE, linkParam.getServerId(), NQA_SENT, linkParam.getHostId(), false);
        if(mwZabbixAPIResult == null || mwZabbixAPIResult.isFail()){return targetIpInfos;}
        List<ItemApplication> applicationList = JSONArray.parseArray(String.valueOf(mwZabbixAPIResult.getData()), ItemApplication.class);
        List<String> itemNames = applicationList.stream().map(s -> s.getName()).collect(Collectors.toList());
        //获取name中括号中的IP数据
        for (String itemName : itemNames) {
            if(!itemName.contains("]")){continue;}
            MwLinkTargetIpInfo targetIpInfo = new MwLinkTargetIpInfo();
            targetIpInfo.setTargetIpAddress(itemName.substring(1, itemName.indexOf("]")));
            targetIpInfos.add(targetIpInfo);
        }
        return targetIpInfos;
    }

    @Override
    public void handlerLinkData(MwNetWorkLinkDto netWorkLinkDto) throws Exception {
        String takeValuePort = netWorkLinkDto.getTakeValuePort();
        String instanceId = null;
        if(takeValuePort.equals(ROOT)){
            instanceId = netWorkLinkDto.getSourceDeviceAsset();
        }
        if(takeValuePort.equals(TARGET)){
            instanceId = netWorkLinkDto.getTargetDeviceAsset();
        }
        createZabbixLink(LinkDetectionWayEnum.NQA,instanceId);
    }

    @Override
    public List<LinkHistoryTrendDto> getLinkHistoryTrend(MwNetWorkLinkDto netWorkLinkDto, LinkParam linkParam) throws Exception {
        List<LinkHistoryTrendDto> historyTrendDtos = new ArrayList<>();
        String takeValuePort = netWorkLinkDto.getTakeValuePort();
        String assetId = null;
        if(takeValuePort.equals(ROOT)){
            assetId = netWorkLinkDto.getSourceDeviceAsset();
        }
        if(takeValuePort.equals(TARGET)){
            assetId = netWorkLinkDto.getTargetDeviceAsset();
        }
        List<InstanceInfoExtend> assetInfo = getTargetDeviceAssetInfo(null, null, Arrays.asList(assetId));
        if(CollectionUtils.isEmpty(assetInfo)){return historyTrendDtos;}
        LinkHistoryTypeEnum historyTypeEnum = LinkHistoryTypeEnum.getHistoryTypeEnum(linkParam.getQueryType());
        log.info("LinkNQAWayHandler{} getLinkHistoryTrend() historyTypeEnum>>>"+historyTypeEnum);
        List<Long> times = BaseUtil.getTimeIntervalByType(linkParam.getStartTime(), linkParam.getEndTime(), linkParam.getDateType());
        switch (historyTypeEnum){
            case FLOW:
                historyTrendDtos = getHistoryTrendData(netWorkLinkDto, linkParam);
                break;
            case DELAY:
                historyTrendDtos = handlerHistoryTrendData(assetInfo.get(0).getMonitorTypeId(),assetInfo.get(0).getMonitorServerId(), Arrays.asList("["+netWorkLinkDto.getDetectionTargetIp()+"]"+PING_MAXRTT),times,linkParam.getHistoryDataType(),linkParam.getValueType());
                break;
            case LOSS_RATE:
                historyTrendDtos = handlerHistoryTrendData(assetInfo.get(0).getMonitorTypeId(),assetInfo.get(0).getMonitorServerId(),Arrays.asList("["+netWorkLinkDto.getDetectionTargetIp()+"]"+NQA_LOSS),times,linkParam.getHistoryDataType(),linkParam.getValueType());
                break;

        }
        return historyTrendDtos;
    }

    private MwLinkCountDto setNqaValueInfo(MwNetWorkLinkDto linkDto,List<ItemApplication> itemApplications){
        MwLinkCountDto countDto = new MwLinkCountDto();
        for (ItemApplication itemApplication : itemApplications) {
            String name = itemApplication.getName();
            String lastvalue = itemApplication.getLastvalue();
            if(name.contains("["+linkDto.getDetectionTargetIp()+"]"+NQA_SUCESS)){//设置状态
                linkDto.setStatus(Double.parseDouble(lastvalue) != 0?NORMAL:ABNORMAL);
                countDto.setNqaSucess(Double.parseDouble(lastvalue));
            }
            if(name.contains("["+linkDto.getDetectionTargetIp()+"]"+PING_AVGRTT)){//设置响应时间
                //单位换算成Ms
                UnitResult unitResult = UnitUtil.getValueMap(lastvalue, MS, itemApplication.getUnits());
                if(unitResult == null){
                    linkDto.setResponseTime(new BigDecimal(lastvalue).setScale(2,BigDecimal.ROUND_HALF_UP).toString()+itemApplication.getUnits());
                }else{
                    linkDto.setResponseTime(unitResult.getValue()+unitResult.getUnits());
                }
            }
            if(name.contains("["+linkDto.getDetectionTargetIp()+"]"+NQA_SENT)){
                countDto.setNqaSent(Double.parseDouble(lastvalue));
            }
        }
        return countDto;
    }
}
